package com.sky.common.generate.core;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;

public class GenerateBase extends GenerateConfig {

    /**
     * 包路径配置
     **/
    protected String packagePath;
    /**
     * 表名
     **/
    protected String tableName;
    /**
     * 模块名
     **/
    protected String moduleName;
    /**
     * 类名
     **/
    protected String className;

    protected List<FieldInfo> fieldList;

    protected FieldInfo fieldInfo;

    /**
     * 需要用该字段查询的方法
     **/
    protected String[] fieldMethod;

    public GenerateBase(String tableName, String moduleName, String className) {
        this.tableName = tableName;
        this.moduleName = moduleName;
        this.className = className;
        this.fieldList = getFieldInfo(tableName);
        fieldInfo = fieldInfoByPrimary(this.fieldList);
    }

    public GenerateBase(String tableName, String moduleName, String className, String... fieldMethod) {
        this.tableName = tableName;
        this.moduleName = moduleName;
        this.className = className;
        this.fieldMethod = fieldMethod;
        this.fieldList = getFieldInfo(tableName);
        fieldInfo = fieldInfoByPrimary(this.fieldList);
    }

    protected GenerateBase(String packagePath, String tableName, String moduleName, String className,
                           List<FieldInfo> fieldList, String[] fieldMethod) {
        this.packagePath = packagePath;
        this.tableName = tableName;
        this.moduleName = moduleName;
        this.className = className;
        this.fieldList = fieldList;
        this.fieldMethod = fieldMethod;
        fieldInfo = fieldInfoByPrimary(this.fieldList);
    }

    private FieldInfo fieldInfoByPrimary(List<FieldInfo> fieldList) {
        FieldInfo fieldInfo = null;
        for (FieldInfo fi : fieldList) {
            if (fi.isPrimary()) {
                fieldInfo = fi;
            }
        }
        return fieldInfo;
    }

    /**
     * 获取生成路径
     **/
    protected String getGeneratePath(String packageName, String suffixName) {
        StringBuilder builder = new StringBuilder();
        builder.append(System.getProperty("user.dir"));
        builder.append(File.separator).append("src").append(File.separator).append("main").append(File.separator).append("java").append(File.separator);
        builder.append(packagePath.replaceAll("\\.", File.separator + File.separator));
        builder.append(File.separator).append(moduleName);
        builder.append(File.separator).append(packageName).append(File.separator);
//        builder.append(File.separator).append(File.separator);
        builder.append(className);
        if (suffixName != null) {
            builder.append(suffixName);
        }
        builder.append(".java");
        return builder.toString();
    }


    /**
     * 写入生成文件
     **/
    protected void writeGenerateFile(byte[] b, String filePath) {
        FileOutputStream fileOutputStream = null;
        File file = new File(filePath);
        try {
            // 判断文件存在且覆盖
            if (file.exists() && !isCoverage) {
                System.out.println("无法覆盖现有文件:" + filePath);
                return;
            }
            System.out.println("生成文件:" + filePath);
            file.getParentFile().mkdirs();
            file.createNewFile();
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(b);
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成包路径
     **/
    protected String generatePackage(String path) {
        return "package " + path + ";\n\n";
    }

    /**
     * 生成引用路径
     **/
    protected String generateImport(String javaText) {
        StringBuilder builder = new StringBuilder();
        Set<String> keySet = importMap.keySet();
        for (String key : keySet) {
            if (javaText.contains(key)) {
                builder.append(importMap.get(key));
            }
        }
        return builder.append("\n").toString();
    }

    /**
     * 首字母大写
     **/
    protected String upper(String field) {
        if (field == null) {
            return null;
        }
        char cr = field.charAt(0);
        return field.replaceFirst(String.valueOf(cr), String.valueOf(cr).toUpperCase());
    }

    /**
     * 首字母小写
     **/
    public String lower(String field) {
        char cr = field.charAt(0);
        return field.replaceFirst(String.valueOf(cr), String.valueOf(cr).toLowerCase());
    }

    /**
     * 数据源
     **/
    private DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(jdbcDriver);
        dataSource.setUrl(jdbcUrl);
        dataSource.setUsername(jdbcUserName);
        dataSource.setPassword(jdbcPassword);
        return dataSource;
    }

    /**
     * 数据类型转换
     **/
    private String dataTypeConvert(String dataType) {
        return dataTypeMap.get(dataType) != null ? dataTypeMap.get(dataType) : dataType;
    }

    /**
     * 处理带下划线的字段,下划线转驼峰
     **/
    private String parseField(String field) {
        if (field.contains("_")) {
            StringBuilder str = new StringBuilder();
            String[] split = field.split("_");
            char cr;
            String fd = null;
            for (int i = 0; i < split.length; i++) {
                if (i == 0) {
                    str.append(split[0]);
                } else {
                    fd = split[i];
                    cr = fd.charAt(0);
                    str.append(fd.replaceFirst(String.valueOf(cr), String.valueOf(cr).toUpperCase()));
                }
            }
            field = str.toString();
        }
        return field;
    }

    private List<FieldInfo> getFieldInfo(String tableName) {
        List<FieldInfo> fieldInfoList = new ArrayList<FieldInfo>();
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        String[] db = jdbcUrl.split("/");
        List<Map<String, Object>> list = jdbcTemplate
                .queryForList("select * from information_schema.columns where table_name ='" + tableName
                        + "' AND TABLE_SCHEMA='" + db[db.length - 1] + "' ORDER BY ordinal_position asc");
        FieldInfo fieldInfo = null;
        StringBuilder fields = new StringBuilder();
        for (Iterator<Map<String, Object>> it = list.iterator(); it.hasNext(); ) {
            Map<String, Object> map = it.next();
            fieldInfo = new FieldInfo();
            fieldInfo.setTableName(tableName);
            fieldInfo.setColumnName(map.get("COLUMN_NAME").toString());
            fieldInfo.setNull("YES".equals(map.get("IS_NULLABLE")));
            fieldInfo.setPrimary("PRI".equals(map.get("COLUMN_KEY")));
            fieldInfo.setUnique("UNI".equals(map.get("COLUMN_KEY")));
            fieldInfo.setComment(map.get("COLUMN_COMMENT").toString());
            fieldInfo.setJavaDataType(dataTypeConvert(map.get("DATA_TYPE").toString()));
            fieldInfo.setJavaColumnName(parseField(map.get("COLUMN_NAME").toString()));
            fieldInfo.setGenerateMethod(isGenerateMethod(fieldInfo.getJavaColumnName()));
            fieldInfo.setAlias(String.valueOf(className.charAt(0)).toLowerCase());
            fieldInfoList.add(fieldInfo);

            fields.append(fieldInfo.getAlias()).append(".").append(fieldInfo.getColumnName()).append(",");
        }
        if (fields.length() > 0) {
            for (FieldInfo info : fieldInfoList) {
                if (info.isUnique() || info.isGenerateMethod() || info.isPrimary()) {
                    info.setColumnNames(fields.substring(0, fields.length() - 1));
                }
            }
        }
        return fieldInfoList;
    }

    private boolean isGenerateMethod(String field) {
        boolean isTrue = false;
        if (fieldMethod != null) {
            for (String str : fieldMethod) {
                if (parseField(str).toLowerCase().equals(field.toLowerCase())) {
                    isTrue = true;
                    break;
                }
            }
        }
        return isTrue;
    }

    public String getPackagePath() {
        return packagePath;
    }

    public void setPackagePath(String packagePath) {
        this.packagePath = packagePath;
    }

}
